﻿using AnesSystem.Models;
using AnesSystem.Services;
using Common;
using Models;
using MongoDB.Bson;
using MongoDB.Driver;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;

namespace AnesSystem.ViewModels
{
    public class DataConvertCtrlViewModel : BaseViewModel<DataConvertCtrlViewModel>
    {
        #region Variables

        private ObservableCollection<TableItem> list = new ObservableCollection<TableItem>();
        private List<HospitalEnum> _hospitals = new List<HospitalEnum>();
        private string _hospital;
        string[] tlTables = new string[] { "ShuQianFangShi", "MaZuiTongYi", "ShuHouFangShi" };
        string[] ntTables = new string[] { "zhiQingTongYi", "shuHouZhenTong", "shuHouFangShi", "yaoPingHaoCai", "nanTongShuQianFangShi" };
        string[] fyTables = new string[] { "intraveAnesthesia", "anesthesiaAgreement", "followUp", "analgesicRecord", "preoperativeInterview", "shuXueZhiQing" };
        string[] dcTables = new string[] { "yaoPingYiZhu", "shuQianFangShi", "shuHouFangShi", "shouShuJiLu", "shouShuHuLi", "maZuiTongYi", "maZuiHuLi",
            "configYaoPingHaoCai", "jiaoJieJiLu", "huLiJiLu2", "shuHouZhenTong", "qingDianJiLu", "anQuanHeCha", "huLiJiLu", "jiaoJieJiLu2", "shuHouHuLi",
            "yaChuangFengXian" , "yaChuangJianKong", "yaChuangJiLu", "shouShuZhiLiao", "jianKongJiLu"};
        int threadCount = 4;
        List<TableItem> noConvertList = new List<TableItem>();
        #endregion

        #region Constructor

        public DataConvertCtrlViewModel()
        {
            foreach (HospitalEnum item in Enum.GetValues(typeof(HospitalEnum)))
            {
                Hospitals.Add(item);
            }
        }

        #endregion

        #region Properties

        public List<HospitalEnum> Hospitals
        {
            get
            {
                return _hospitals;
            }

            set
            {
                _hospitals = value;
                RaisePropertyChanged("Hospitals");
            }
        }

        public ObservableCollection<TableItem> List
        {
            get
            {
                return list;
            }

            set
            {
                list = value;
                RaisePropertyChanged("List");
            }
        }

        public string SelHospital
        {
            get
            {
                return _hospital;
            }

            set
            {
                _hospital = value;
                RaisePropertyChanged("SelHospital");
            }
        }

        public bool IsEnabled { get; set; }

        #endregion

        #region 依赖属性

        #endregion

        #region Event

        #endregion

        #region Private Methods

        private void FillData(BsonElement c, object tObj, IEnumerable<PropertyInfo> tPros)
        {
            try
            {
                Util.ExtensionMethods.FillData(c, tObj, tPros);
                //foreach (var tPro in tPros)
                //{
                //    if (tPro != null)
                //    {
                //        //如果是实体类进入此if
                //        if (tPro.PropertyType.FullName.Contains("AnesSystem.Models") && !c.Value.IsBsonArray && !c.Name.ToLower().Equals("tables"))
                //        {
                //            if (tPro.Name.ToLower().Equals(c.Name.ToLower()))
                //            {
                //                object obj = Activator.CreateInstance(tPro.PropertyType);
                //                if (c.Value.IsBsonDocument)
                //                {
                //                    foreach (var e in c.Value.ToBsonDocument().Elements)
                //                    {
                //                        try
                //                        {
                //                            if (e.Value.IsBsonNull) continue;
                //                            FillData(e, obj, obj.GetType().GetProperties());
                //                        }
                //                        catch (Exception ex)
                //                        {
                //                            Common.LogHelper.Error("BaseService", ex);
                //                        }
                //                    }
                //                }
                //                if (c.Name.Equals("shuQianFangShi"))//之前对象名称
                //                {

                //                }
                //                tPro.SetValue(tObj, obj);
                //                break;
                //            }
                //        }
                //        //普通类型进入此方法
                //        else if (c.Name.Replace("_", "").ToLower().Equals(tPro.Name.ToLower()))
                //        {
                //            if (c.Value.IsBoolean)
                //            {
                //                if (c.Name.Equals("mzccbw_w"))
                //                {
                //                    c.Name.Equals("");
                //                }
                //                tPro.SetValue(tObj, c.Value.AsBoolean);
                //                break;
                //            }
                //            else if (c.Value.IsBsonDateTime)
                //            {
                //                tPro.SetValue(tObj, c.Value.AsDateTime);
                //                break;
                //            }
                //            else if (c.Value.IsBsonNull)
                //            {
                //                //tPro.SetValue(tObj, c.Value.asn);
                //                break;
                //            }
                //            else if (c.Value.IsInt32)
                //            {
                //                tPro.SetValue(tObj, c.Value.AsInt32);
                //                break;
                //            }
                //            else if (c.Value.IsObjectId)
                //            {
                //                tPro.SetValue(tObj, c.Value.AsObjectId);
                //                break;
                //            }
                //            else if (c.Value.IsString)
                //            {
                //                tPro.SetValue(tObj, c.Value.AsString);
                //                break;
                //            }
                //            else if (c.Value.IsBsonArray)
                //            {
                //                BsonArray arr = c.Value.AsBsonArray;
                //                if (arr.Count != 0)
                //                {
                //                    //ArrayList[] entityList = new object[arr.Count];
                //                    BindingFlags flag = BindingFlags.Instance | BindingFlags.Public;
                //                    MethodInfo methodInfo = tPro.PropertyType.GetMethod("Add", flag);
                //                    object arrObjs = Activator.CreateInstance(tPro.PropertyType);
                //                    int i = 0;
                //                    foreach (var o in arr)
                //                    {
                //                        object arrObj = Activator.CreateInstance(Type.GetType(tPro.PropertyType.GetGenericArguments()[0].FullName));
                //                        foreach (var e in o.AsBsonDocument)
                //                        {
                //                            FillData(e, arrObj, arrObj.GetType().GetProperties());
                //                        }
                //                        methodInfo.Invoke(arrObjs, new object[] { arrObj });//相当于List<T>调用Add方法
                //                    }
                //                    tPro.SetValue(tObj, arrObjs);
                //                }
                //                break;
                //            }
                //        }
                //    }
                //}

            }
            catch (Exception ex)
            {
                Common.LogHelper.Error("BaseService", ex);
            }
        }

        private void TaskInvoke(List<BsonDocument> list, TableItem item)
        {

            try
            {
                int curCount = list.Count;
                int finish = 0;
                List<object> insetList = new List<object>();
                List<ObjectId> listId = new List<ObjectId>();
                //循环对象集合 dObj是BsonDocument
                foreach (var dObj in list)
                {
                    try
                    {
                        //需要将数据库存储的对象转换到哪个实体类
                        string nameSpace = item.TableName.ToLower().Equals("patientLink".ToLower()) ? HospitalConfig.Instance.DicHospitals[SelHospital].ModelNameSpace : "AnesSystem.Models";
                        string tableName = nameSpace + "." + item.TableName.Substring(0, 1).ToUpper() + item.TableName.Remove(0, 1) + "Model";
                        Type type = Type.GetType(tableName);
                        if (type == null)
                        {
                            Console.Write(HospitalConfig.Instance.DicHospitals[SelHospital].ModelNameSpace +
                                   item.TableName.Substring(0, 1).ToUpper() + item.TableName.Remove(0, 1) + "Model");
                            continue;
                        }
                        object tObj = Activator.CreateInstance(type);

                        //c是BsonElement，BsonDocument的BsonElement
                        foreach (var c in dObj)
                        {
                            IEnumerable<PropertyInfo> tPros = tObj.GetType().GetProperties();
                            //填充对象
                            FillData(c, tObj, tPros);
                            try
                            {
                                #region 德昌
                                if (tObj is AnesSystem.Models.Model.Hospital.SC.SCDC.PatientLinkModel)
                                {
                                    DeChangTableModel tfdc = (tObj as AnesSystem.Models.Model.Hospital.SC.SCDC.PatientLinkModel).DeChangTable;
                                    if (tfdc == null) continue;
                                    PropertyInfo[] pros = tfdc.GetType().GetProperties();
                                    AnesSystem.Models.Model.Hospital.SC.SCDC.PatientLinkModel patient = tObj as AnesSystem.Models.Model.Hospital.SC.SCDC.PatientLinkModel;
                                    patient.Tables = new Dictionary<string, CommonTableModel>();
                                    FillDeChangTableValue(patient, pros, dcTables);
                                }
                                #endregion

                                #region 南桐

                                if (tObj is AnesSystem.Models.Model.Hospital.CQ.CQNT.PatientLinkModel)
                                {
                                    TableForNanTong tfnt = (tObj as AnesSystem.Models.Model.Hospital.CQ.CQNT.PatientLinkModel).TableForNanTong;
                                    if (tfnt == null) continue;
                                    PropertyInfo[] pros = tfnt.GetType().GetProperties();
                                    AnesSystem.Models.Model.Hospital.CQ.CQNT.PatientLinkModel patient = tObj as AnesSystem.Models.Model.Hospital.CQ.CQNT.PatientLinkModel;
                                    patient.Tables = new Dictionary<string, CommonTableModel>();
                                    FillTableValue(patient, pros, ntTables);
                                }
                                #endregion

                                #region 铜梁

                                if (tObj is AnesSystem.Models.Model.Hospital.CQ.CQTL.PatientLinkModel && false)
                                {
                                    AnesSystem.Models.Model.Hospital.CQ.CQTL.PatientLinkModel patient = tObj as AnesSystem.Models.Model.Hospital.CQ.CQTL.PatientLinkModel;
                                    patient.Tables = new Dictionary<string, CommonTableModel>();
                                    PropertyInfo[] pros = patient.GetType().GetProperties();
                                    FillTableValue(patient, pros, tlTables);
                                }

                                #endregion

                                #region 重庆妇幼

                                if (tObj is AnesSystem.Models.Model.Hospital.CQ.CQFY.PatientLinkModel)
                                {
                                    AnesSystem.Models.Model.Hospital.CQ.CQFY.PatientLinkModel patient = tObj as AnesSystem.Models.Model.Hospital.CQ.CQFY.PatientLinkModel;
                                    patient.Tables = new Dictionary<string, CommonTableModel>();
                                    PropertyInfo[] pros = patient.GetType().GetProperties();
                                    FillTableValue(patient, pros, fyTables);
                                }

                                #endregion
                            }
                            catch (Exception ex)
                            {
                                Common.LogHelper.Error(this.GetType(), ex);
                            }
                        }
                        item.CompatedCount++;
                        item.Jindu = item.CompatedCount * 1.0 / item.DataCount * 100;
                        insetList.Add(tObj);
                        ObjectId id = (ObjectId)tObj.GetType().GetProperty("Id").GetValue(tObj);
                        listId.Add(id);
                    }
                    catch (Exception ex)
                    {
                        Common.LogHelper.Error(this.GetType(), ex);
                    }
                }
                if (insetList != null && insetList.Count >= 1)
                {
                    HelperManager.Instance.MongoDB.BatchDelete<ObjectId>(listId, item.TableName);
                    try
                    {
                        HelperManager.Instance.MongoDB.BatchInsert(insetList, item.TableName);
                        if (item.CompatedCount == item.DataCount)
                        {
                            item.State = 1;
                        }
                    }
                    catch (Exception ex)
                    {
                        item.State = 2;
                        HelperManager.Instance.MongoDB.BatchInsert(list, item.TableName);
                        Common.LogHelper.Error(this.GetType(), ex);
                    }
                }
                else
                {
                    item.State = 3;
                }
                converttingCount--;
                convertedCount++;
            }
            catch (Exception ex)
            {
                Common.LogHelper.Error(this.GetType(), ex);
            }
        }

        private void FillDeChangTableValue(AnesSystem.Models.Model.Hospital.SC.SCDC.PatientLinkModel patient, PropertyInfo[] pros, string[] tables)
        {
            foreach (var pro in pros)
            {
                foreach (string table in tables)
                {
                    if (table.ToUpper().Equals(pro.Name.ToUpper()))
                    {
                        if (pro.GetValue(patient.DeChangTable) == null)
                        {
                            break;
                        }
                        else
                        {
                            patient.Tables.Add(table, CreateDeChangTable(pro, patient, table));
                            pro.SetValue(patient.DeChangTable, null);
                            break;
                        }

                    }
                }
            }
        }

        private void FillTableValue(Models.PatientLinkModel patient, PropertyInfo[] pros, string[] tables)
        {
            foreach (var pro in pros)
            {
                foreach (string table in tables)
                {
                    if (table.ToUpper().Equals(pro.Name.ToUpper()))
                    {
                        if (pro.GetValue(patient) == null)
                        {
                            break;
                        }
                        else
                        {
                            patient.Tables.Add(table, CreateTable(pro, patient, table));
                            pro.SetValue(patient, null);
                            break;
                        }

                    }
                }
            }
        }

        private void ItemConvert(TableItem item)
        {
            item.State = 4;
            item.Jindu = 0;
            item.DataCount = HelperManager.Instance.MongoDB.Count<BsonDocument>(item.TableName);
            int pageSize = item.TableName.Equals("patientLink") ? 200 : 5000;
            long forCount = item.DataCount / pageSize;
            //表下面的对象
            List<BsonDocument> dList = null;
            if (forCount > 1)
            {
                Task.Factory.StartNew(delegate
                {
                    for (int i = 1; i <= forCount + 1; i++)
                    {
                        if (i == forCount + 1)
                        {
                            if ((int)(item.DataCount % pageSize) != 0)
                                dList = HelperManager.Instance.MongoDB.PageListAsync<BsonDocument>(i, (int)(item.DataCount % pageSize), item.TableName).Result;
                            else break;
                        }
                        else
                        {
                            dList = HelperManager.Instance.MongoDB.PageListAsync<BsonDocument>(i, pageSize, item.TableName).Result;
                        }
                        TaskInvoke(dList, item);
                    }
                });
            }
            else
            {
                Task.Factory.StartNew((Action)delegate
               {
                   dList = HelperManager.Instance.MongoDB.FindAsync<BsonDocument>(new BsonDocument(), item.TableName).Result;
                   TaskInvoke(dList, item);
               });
            }
        }
        private CommonTableModel CreateDeChangTable(PropertyInfo pro, AnesSystem.Models.Model.Hospital.SC.SCDC.PatientLinkModel patient, string table)
        {
            try
            {
                var obj = pro.GetValue(patient.DeChangTable);
                XmlDocument doc = new XmlDocument();
                XmlElement root = doc.CreateElement("TableName");
                root.SetAttribute("value", table);
                PropertyInfo[] iPros = obj.GetType().GetProperties();
                foreach (var iPro in iPros)
                {
                    if (iPro.GetValue(obj) == null) continue;
                    XmlElement node = doc.CreateElement(iPro.Name.ToLower());
                    node.InnerText = iPro.GetValue(obj).ToString();
                    root.AppendChild(node);
                }
                doc.AppendChild(root);
                CommonTableModel tableModel = new CommonTableModel();
                tableModel.TableName = table;
                tableModel.XmlContent = string.Format("<?xml version=\"1.0\" encoding=\"utf - 8\"?>{0}", doc.InnerText);
                return tableModel;
            }
            catch (Exception ex)
            {
                return new CommonTableModel();
            }
        }

        private CommonTableModel CreateTable(PropertyInfo pro, object tfnt, string table)
        {
            try
            {
                var obj = pro.GetValue(tfnt);
                XmlDocument doc = new XmlDocument();
                XmlElement root = doc.CreateElement("TableName");
                root.SetAttribute("value", table);
                PropertyInfo[] iPros = obj.GetType().GetProperties();
                foreach (var iPro in iPros)
                {
                    if (iPro.GetValue(obj) == null) continue;
                    XmlElement node = doc.CreateElement(iPro.Name.ToLower());
                    node.InnerText = iPro.GetValue(obj).ToString();
                    root.AppendChild(node);
                }
                doc.AppendChild(root);
                CommonTableModel tableModel = new CommonTableModel();
                tableModel.TableName = table;
                tableModel.XmlContent = string.Format("<?xml version=\"1.0\" encoding=\"utf - 8\"?>{0}", doc.InnerText);
                return tableModel;
            }
            catch (Exception ex)
            {
                return new CommonTableModel();
            }
        }

        int converttingCount = 0;
        int convertedCount = 0;

        private void MonitorNoConvertList()
        {
            noConvertList.Clear();
            List<TableItem> needConvertList = list.Where(O => O.IsSelected).ToList();
            Task.Factory.StartNew(delegate
            {
                while (true)
                {
                    if (convertedCount == needConvertList.Count) break;
                    if (converttingCount == threadCount)
                    {
                        Thread.Sleep(2000);
                        continue;
                    }
                    for (int i = needConvertList.Count - 1; i >= 0; i--)
                    {
                        TableItem item = needConvertList[i];
                        if (convertedCount == threadCount) break;
                        if (item.State == 0 && item.IsSelected)
                        {
                            converttingCount++;
                            item.State = 4;
                            ItemConvert(item);
                            needConvertList.RemoveAt(i);
                        }
                    }
                    Thread.Sleep(2000);
                }
            });
        }

        #endregion

        #region Public/Protected Methods

        public void ChangeHospital()
        {
            List.Clear();
            Hospital cur = HospitalConfig.Instance.DicHospitals[SelHospital];
            //设置MongoDB连接信息   
            HelperManager.Instance.MongoDB.SetMongo(cur.Ip, cur.Port, cur.DbName);
            List<BsonDocument> listCollection = HelperManager.Instance.MongoDB.GetCollections();
            int i = 1;
            foreach (var col in listCollection)
            {
                TableItem table = new TableItem()
                {
                    Index = i,
                    TableName = col.Values.ElementAt(0).AsString,
                    State = 0
                };
                List.Add(table);
                i++;
            }
        }

        public void BeginConvert()
        {
            //MonitorNoConvertList();
            foreach (var item in list)
            {
                if (item.IsSelected)
                    ItemConvert(item);
            }
        }

        public void Convert(TableItem item)
        {
            ItemConvert(item);
        }

        #endregion

        #region EventHandlers

        #endregion

        public class TableItem : ObservableObject
        {
            private int index = 0;
            private string tableName;
            private int state;
            private double jindu = 0;
            private long compatedCount = 0;
            private long dataCount = 0;
            private bool isSelected = true;
            private string tip = "未完成";
            public string TableName
            {
                get
                {
                    return tableName;
                }

                set
                {
                    tableName = value;
                }
            }

            /// <summary>
            /// 完成状态 0：未完成 1：已完成 2：转换失败 3：无数据 4：进行中
            /// </summary>
            public int State
            {
                get
                {
                    return state;
                }

                set
                {
                    state = value;
                    switch (value)
                    {
                        case 0:
                            Tip = "未完成";
                            break;
                        case 1:
                            Tip = "已完成";
                            break;
                        case 2:
                            Tip = "转换失败";
                            break;
                        case 3:
                            Tip = "无数据";
                            break;
                        case 4:
                            Tip = "进行中";
                            break;
                    }
                    RaisePropertyChanged("State");
                }
            }

            public double Jindu
            {
                get
                {
                    return jindu;
                }

                set
                {

                    jindu = (float)value;
                    RaisePropertyChanged("Jindu");
                }
            }

            public int Index
            {
                get
                {
                    return index;
                }

                set
                {
                    index = value;
                }
            }

            public bool IsSelected
            {
                get
                {
                    return isSelected;
                }

                set
                {
                    isSelected = value;
                    RaisePropertyChanged("IsSelected");
                }
            }

            public string Tip
            {
                get
                {
                    return tip;
                }

                set
                {
                    tip = value;
                    RaisePropertyChanged("Tip");
                }
            }

            public long CompatedCount
            {
                get
                {
                    return compatedCount;
                }

                set
                {
                    compatedCount = value;
                }
            }

            public long DataCount
            {
                get
                {
                    return dataCount;
                }

                set
                {
                    dataCount = value;
                }
            }
        }
    }
}
